
const { Controller } = require('egg')
const fs = require('fs')
const path = require('path')
class userController extends Controller {
    /**
     * 异步注册用户
     * 此方法用于处理用户注册请求它首先验证输入规则，然后检查账户、邮箱和电话是否已被注册，
     * 如果未被注册，则调用服务层进行用户注册
     */
    async register() {
        // 获取上下文对象
        const { ctx } = this;
        // 定义注册的验证规则
        const registerRules = {
            account: { required: true, type: 'account' }, // 账户规则：必填，类型为账户
            password: { required: true, type: 'password' }, // 密码规则：必填，类型为密码
            email: { required: true, type: 'email' }, // 邮箱规则：必填，类型为邮箱
            phone: { required: true, type: 'phone' }, // 电话规则：必填，类型为电话
        }
        // 验证注册信息的合法性
        ctx.validate(registerRules);
        // 提取注册信息中的账户、邮箱和电话
        const { account, email, phone } = ctx.request.body;
        // 检查账户是否已存在
        if (await ctx.service.user.findaccount(account)) {
            ctx.throw(404, '账户已经存在');
        }

        // 检查邮箱是否已存在
        if (await ctx.service.user.findemail(email)) {
            ctx.throw(404, '邮箱已经存在');
        }

        // 检查电话是否已存在
        if (await ctx.service.user.findphone(phone)) {
            ctx.throw(404, '手机号已经存在');
        }
        try {
            // 调用服务层进行用户注册
            const data = await this.service.user.registUser(ctx.request.body);
            // 设置返回信息：注册成功
            ctx.body = {
                code: 200,
                msg: '注册成功',
                data: data
            }

        } catch (err) {
            // 日志记录错误
            console.log(err);
            // 设置返回信息：注册失败
            ctx.body = {
                code: 500,
                msg: '注册失败',
                data: err
            }
        }
    }

    /**
     * 异步登录方法
     * 
     * 本方法通过接收客户端的登录信息，验证用户账户和密码的正确性，并在验证成功后返回JWT令牌
     * 使用场景包括但不限于用户登录接口，通过该方法可以验证用户身份并获取用于身份验证的令牌
     * 
     * @throws {Error} 若账户不存在或密码错误，抛出404错误并附带相应消息
     * @returns {Object} 返回包含状态码、消息和用户数据（含令牌）的对象
     */
    async login() {
        // 获取上下文对象
        const { ctx } = this;
        // 解构请求体中的登录信息
        const { account, password } = ctx.request.body;
        // 查询数据库中是否存在该账户
        const user = await ctx.service.user.findaccount(account);
        // 若账户不存在，则抛出404错误并提示
        if (!user) {
            ctx.throw(404, '账户不存在');
        }
        // 检查密码是否匹配，如果不匹配，则抛出404错误并提示
        if (ctx.helper.md5(password) !== user.password) {
            ctx.throw(404, '密码错误');
        }
        // 为验证成功的用户创建JWT令牌
        const token = await ctx.helper.createJwt({ user });
        // 获取用户信息，准备返回给客户端
        const userinfo = user._doc;
        // 从用户信息中删除密码字段，以安全起见
        delete userinfo.password;
        // 组织返回的数据结构
        ctx.body = {
            code: 200,
            msg: '登录成功',
            data: {
                // 使用展开操作符将用户信息和令牌合并到一个对象中
                ...userinfo,
                token
            }
        };
    }

    /**
     * 异步列表方法
     * 该方法用于获取用户列表
     * 
     * @param {Object} ctx - 上下文对象，包含请求和响应等信息
     * @param {number} page - 请求的页码，默认为1
     * @param {number} pagesize - 每页显示的数量，默认为10
     * 
     * @throws {Error} 如果服务调用失败，则抛出500错误
     */
    async list() {
        const { ctx } = this;
        const { page = 1, pagesize = 10 } = ctx.params;
        try {
            // 调用服务层方法获取用户列表和总数
            const { list, count } = await ctx.service.user.getUserList(page, pagesize)
            // 返回成功响应，包含用户列表和总数
            ctx.body = {
                code: 200,
                msg: '获取用户列表成功',
                data: {
                    list,
                    count
                }
            }
        }
        catch (err) {
            // 如果发生错误，抛出错误并附带错误信息
            ctx.throw(500, err)
        }
    }

    /**
     * 异步上传头像
     * 该函数处理用户上传的头像文件，并将其移动到服务器的指定位置
     */
    async uploadavater() {
        // 获取上下文对象
        const { ctx } = this;
        // 从请求中获取文件
        const file = ctx.request.files[0];
        // 如果没有文件上传，则抛出错误
        if (!file) {
            ctx.throw(400, 'No file uploaded');
        }
        // 生成文件名，使用用户ID和文件扩展名
        const filename = ctx.userinfo._id + '.' + (file.filename.split('.'))[file.filename.split('.').length - 1]
        // 拼接文件的目标路径
        const targetPath = path.join(this.config.baseDir, 'app/public/uploads', path.basename(filename));
        // 将文件从临时路径移动到目标路径
        try {
            await fs.promises.rename(file.filepath, targetPath);
            // 更新用户头像信息
            await ctx.service.user.updateUser(ctx.userinfo._id, { avater: '/uploads/' + filename });
            // 更新响应体为上传成功信息
            ctx.body = {
                code: 200,
                msg: '上传成功',
                data: {
                    url: '/uploads/' + filename
                }
            };
        } catch {
            // 如果移动文件失败，抛出错误
            ctx.throw(500, '上传失败');
        }
    }


    async updateuser() {
        const { ctx } = this;
        const data = ctx.request.body;
        const { _id } = ctx.userinfo;
        let canchangekey = ['account', 'nickname', 'email', 'phone']
        for (let key in data) {
            if (!canchangekey.includes(key)) {
                ctx.throw(402, '不能修改该字段')
                return
            }
        }
        try {
            const dbback = await ctx.service.user.updateUser(_id, data)
            const userinfo = JSON.parse(JSON.stringify(dbback))
            delete userinfo.password;
            ctx.body = {
                code: 200,
                msg: '更新成功',
                data: userinfo
            }
        } catch {
            ctx.body = {
                code: 500,
                msg: '更新失败',
                data: err
            }
        }

    }

    async getuserinfo() {
        const { ctx } = this;
        const { userid } = ctx.params
        try {
            const userinfo = await ctx.service.user.getUserInfo(userid)
            const data = JSON.parse(JSON.stringify(userinfo))
            delete data.password
            ctx.body = {
                code: 200,
                msg: '获取用户信息成功',
                data: data
            }
        } catch {
            ctx.throw(500, '获取用户信息失败')
        }
    }

    async subscribe() {
        const { ctx } = this
        const {_id} = ctx.userinfo
        const { subscribeid } = ctx.params
        try {
            const dbback = await ctx.service.user.getSubscribe(_id, subscribeid)
            if (dbback) {
                ctx.status = 401
                ctx.body = {
                    code: 401,
                    msg: '已关注',
                }
                return
            }
            await ctx.service.user.subscribe(_id, subscribeid)
            const {subscribecount} = await ctx.service.user.getUserInfo(_id)
            await ctx.service.user.updateUser(_id,{subscribecount:subscribecount+1})
            ctx.body = {
                code: 200,
                msg: '关注成功',
            }

        } catch(err) {
            console.log(err)
            ctx.throw(500, '关注失败')
        }

    }

    async dissubscribe() {
        const { ctx } = this
        const {_id} = ctx.userinfo
        const { subscribeid } = ctx.params
        try {
            const dbback = await ctx.service.user.getSubscribe(_id, subscribeid)
            if (!dbback) {
                ctx.status = 401
                ctx.body = {
                    code: 401,
                    msg: '还未关注该频道',
                }
                return
            }
            await ctx.service.user.dissubscribe(_id, subscribeid)
            const {subscribecount} = await ctx.service.user.getUserInfo(_id)
            await ctx.service.user.updateUser(_id,{subscribecount:subscribecount - 1})
            ctx.body = {
                code: 200,
                msg: '取消关注成功',
            }

        } catch(err) {
            console.log(err)
            ctx.throw(500, '取消关注失败')
        }

    }

    async subscribelist(){
        const { ctx } = this
        const {pagesize=10,page = 1} = ctx.query
        try{
            const dbback = await ctx.service.user.getSubscribeList(page,pagesize,ctx.userinfo._id)
            ctx.body = {
                code:200,
                msg:'获取关注列表成功',
                data:dbback
            }
        }catch{
            ctx.throw(500,'获取关注列表失败')
        }
    }

    async fanslist(){
        const { ctx } = this
        const {subscribeid} = ctx.params
        const {pagesize=10,page = 1} = ctx.query
        try{
            const dbback = await ctx.service.user.getFansList(page,pagesize,subscribeid)
            ctx.body = {
                code:200,
                msg:'获取粉丝列表成功',
                data:dbback
            }
        }catch{
            ctx.throw(500,'获取粉丝列表失败')
        }
    }
}

module.exports = userController